package com.websocket.hander;

public class MatchPath {
    public static boolean match(String pattern, String path) {
        if ("".equals(pattern)) return false;
        if ("/**".equals(pattern)) return true;

        String[] ptmArr = splitPath(pattern);
        String[] pathArr = splitPath(path);

        for (int ptmIdx = 0, pathIdx = 0; ptmIdx < ptmArr.length; ptmIdx++) {
            if ("**".equals(ptmArr[ptmIdx])) {
                if (ptmIdx == ptmArr.length - 1) return true;

                int endI = findNextMoreFlag(ptmArr, ptmIdx + 1);
                if (endI == -1) {
                    return matchRev(ptmArr, ptmIdx + 1, pathArr, pathIdx);
                }
                pathIdx = match(ptmArr, ptmIdx + 1, endI, pathArr, pathIdx);
                if (pathIdx == -1) return false;
                ptmIdx = endI - 1;
            } else {
                int endI = findNextMoreFlag(ptmArr, ptmIdx + 1);
                if (endI == -1) {
                    pathIdx = matchAct(ptmArr, ptmIdx, ptmArr.length, pathArr, pathIdx);
                    return pathIdx != -1 && pathIdx == pathArr.length;
                }
                pathIdx = matchAct(ptmArr, ptmIdx, endI, pathArr, pathIdx);
                if (pathIdx == -1) return false;
                ptmIdx = endI - 1;
            }
        }
        return true;
    }

    private static int matchAct(String[] ptmArr, int ptmStart, int ptmEnd, String[] pathArr, int pathStart) {
        if (ptmEnd - ptmStart > pathArr.length - pathStart) return -1;
        int i = 0;
        for (; ptmStart + i < ptmEnd; i++) {
            String ptm = ptmArr[ptmStart + i];
            String path = pathArr[pathStart + i];
            if ("*".equals(ptm)) continue;
            if (!ptm.equals(path)) return -1;
        }
        return pathStart + i;
    }

    private static boolean matchRev(String[] ptmArr, int ptmStart, String[] pathArr, int pathStart) {
        for (int i = 1; ; i++) {
            int ptmIdx = ptmArr.length - i;
            int pathIdx = pathArr.length - i;
            if ("*".equals(ptmArr[ptmIdx])) continue;
            if (!ptmArr[ptmIdx].equals(pathArr[pathIdx]))
                return false;
            if (ptmIdx == ptmStart) return true;
            if (pathStart == pathIdx) return false;
        }
    }

    private static int match(String[] ptmArr, int ptmStart, int ptmEnd, String[] pathArr, int pathStart) {
        int record = -1, ptmIdx = ptmStart, pathIdx = pathStart;
        // 找到 ptm 开头
        for (; ptmIdx < ptmEnd; ptmIdx++) {
            String ptm = ptmArr[ptmIdx];
            if ("*".equals(ptm)) {
                pathIdx++;
                continue;
            }
            for (int j = pathIdx; j < pathArr.length; j++) {
                if (ptm.equals(pathArr[j])) {
                    record = j;
                    break;
                }
            }
            break;
        }
        // 没找到
        if (record == -1) return -1;

        if (ptmEnd - ptmIdx > pathArr.length - record) return -1;

        int inr = 1;
        for (; ptmIdx + inr < ptmEnd; inr++) {
            if (!ptmArr[ptmIdx + inr].equals(pathArr[record + inr])) {
                return match(ptmArr, ptmStart, ptmEnd, pathArr, pathStart + 1);
            }
        }
        return record + inr;
    }

    private static int findNextMoreFlag(String[] arr, int start) {
        for (int i = start; i < arr.length; i++) {
            if ("**".equals(arr[i])) return i;
        }
        return -1;
    }

    private static String[] splitPath(String path) {
        String[] strings = path.split("/");
        boolean pre = "".equals(strings[0]);
        boolean suf = "".equals(strings[strings.length - 1]);
        if (!pre && !suf) return strings;

        int length = pre && suf ? Math.max(strings.length - 2, 0) : strings.length - 1;
        String[] arr = new String[length];

        for (int i = 0, j = 0; i < strings.length; i++) {
            if (pre && i == 0) continue;
            if (suf && i == strings.length - 1) break;
            arr[j++] = strings[i];
        }
        return arr;
    }
}
